package org.whb.basic.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.whb.basic.constant.LoginConstant;
import org.whb.basic.dto.LoginDto;
import org.whb.basic.exception.BusinessException;
import org.whb.basic.service.ILoginService;
import org.whb.basic.util.AjaxResult;
import org.whb.basic.util.HttpClientUtils;
import org.whb.basic.util.MD5Utils;
import org.whb.basic.util.StrUtils;
import org.whb.user.domain.Logininfo;
import org.whb.user.domain.User;
import org.whb.user.domain.WxUser;
import org.whb.user.mapper.LogininfoMapper;
import org.whb.user.mapper.UserMapper;
import org.whb.user.mapper.WxUserMapper;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class LoginServiceImpl implements ILoginService {

    @Autowired
    private LogininfoMapper logininfoMapper;

    @Autowired
    private WxUserMapper wxUserMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private UserMapper userMapper;

    /**
     * 用户名登录
     * @param dto
     * @return
     */
    @Override
    public Map<String, Object> account(LoginDto dto) {
        //一、传入数据不能为空
        if (StringUtils.isEmpty(dto.getUsername())
                ||StringUtils.isEmpty(dto.getPassword())
                ||StringUtils.isEmpty(dto.getType())){
            throw new BusinessException("请输入登录信息！！！");
        }
        //二、查找数据库中是否有该用户
        Logininfo logininfo = logininfoMapper.loadByUsernameAndType(dto);
        if (logininfo==null){ //查找不到，证明该用户不存在
            throw new BusinessException("用户名或者密码不正确！！！");
        }

        //三、判断密码是否一致
        String salt = logininfo.getSalt();//获得盐值
        //对输入的密码加盐加密
        String loginPassword = MD5Utils.encrypByMd5(dto.getPassword() + salt);
        String rightPassword = logininfo.getPassword(); //注册的时候密码加密加盐了
        if(!rightPassword.equals(loginPassword)){
            throw new BusinessException("用户名或者密码不正确！！！");
        }
        //生成token，存到redis中，并且设置有效期为30分钟
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);

        //将token返回到前端
        Map<String,Object> map = new HashMap();
        map.put("token", token);

        //将logininfo返回前端，敏感信息置空
        logininfo.setPassword("");
        logininfo.setSalt("");
        map.put("logininfo", logininfo);

        return map;
    }

    /**
     * 扫码登录
     * @param param
     * @return
     */
    @Override
    public AjaxResult wechat(Map<String, String> param) {
        String code = param.get("code");
        if (!StringUtils.hasLength(code)){
            throw new BusinessException("系统错误");
        }
        //通过code去微信拿openid和token
        String getTokenUrl= LoginConstant.WX_USER_GET_TOKEN_URL
                .replace("APPID", LoginConstant.APPID)
                .replace("SECRET", LoginConstant.SECRET)
                .replace("CODE", code);
        String wxToken = HttpClientUtils.httpGet(getTokenUrl);
        JSONObject jsonObject = JSON.parseObject(wxToken);
        String accessToken = jsonObject.getString("access_token");
        String openid = jsonObject.getString("openid");
        //查看该openid是否已经存在
        //1、已经存在openid且userid不为空，直接登录
        WxUser wxUser = wxUserMapper.loadByOpenId(openid);
        if (wxUser!=null && wxUser.getUser_id() != null){
            //通过User_id查找logininfo
            Logininfo logininfo = logininfoMapper.loadByUserId(wxUser.getUser_id());

            String token = UUID.randomUUID().toString();
            redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);

            //将token返回到前端
            Map<String,Object> map = new HashMap();
            map.put("token", token);

            //将logininfo返回前端，敏感信息置空
            logininfo.setPassword("");
            logininfo.setSalt("");
            map.put("logininfo", logininfo);
            return new AjaxResult().setResultObj(map);
        }else { //2、如果不存在就将openid和token，封装返回
            String resultObj = "accessToken="+accessToken+"&openid="+openid;
            return new AjaxResult().setSuccess(false).setResultObj(resultObj);
        }
    }


    /**
     * 微信绑定
     * @param param
     * @return
     */
    @Override
    public Map<String, Object> binderWechat(Map<String, String> param) {
        //1、空校验
        String phone = param.get("phone");
        String verifyCode = param.get("verifyCode");
        String accessToken = param.get("accessToken");
        String openid = param.get("openid");
        if(StringUtils.isEmpty(phone)
                || StringUtils.isEmpty(verifyCode)
                || StringUtils.isEmpty(accessToken)
                || StringUtils.isEmpty(openid)){
            throw new BusinessException("请输入正确的手机号或验证码！！！");
        }
        //2、验证码校验
        String redisKey= LoginConstant.WX_BINDER+phone;
        Object rightVerifyCodeAndTime = redisTemplate.opsForValue().get(redisKey);
        if(StringUtils.isEmpty(rightVerifyCodeAndTime)){
            throw new BusinessException("验证码已失效，请重新获取验证码！！！");
        }
        String rightCode = rightVerifyCodeAndTime.toString().split(":")[0];
        if(!verifyCode.equals(rightCode)){
            throw new BusinessException("验证码错误，请输入正确的验证码！！！");
        }
        //获取微信个人信息
        String getUrl=LoginConstant.WX_USER_GET_URL
                        .replace("ACCESS_TOKEN", accessToken)
                        .replace("OPENID", openid);
        String unionID = HttpClientUtils.httpGet(getUrl);
        WxUser wxUser = JSONObject.parseObject(unionID, WxUser.class);
        //判断该手机号是否已被注册
        User user = userMapper.loadByPhone(phone);
        Logininfo logininfo = null;
        if(user == null){
            user = initUser(phone);
            logininfo = user2Logininfo(user);
            logininfoMapper.save(logininfo);
            user.setLogininfo_id(logininfo.getId());
            userMapper.save(user);
        }else {
            logininfo = logininfoMapper.loadById(user.getLogininfo_id());
        }
        wxUser.setUser_id(user.getId());
        wxUserMapper.save(wxUser);

        //免密登录
        String token = UUID.randomUUID().toString();
        redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);

        //将token返回到前端
        Map<String,Object> map = new HashMap();
        map.put("token", token);

        //将logininfo返回前端，敏感信息置空
        logininfo.setPassword("");
        logininfo.setSalt("");
        map.put("logininfo", logininfo);
        return map;
    }

    private Logininfo user2Logininfo(User user) {
        Logininfo logininfo = new Logininfo();
        BeanUtils.copyProperties(user, logininfo);
        logininfo.setType(1);
        logininfo.setDisable(1);
        return logininfo;
    }

    private User initUser(String phone) {
        User user = new User();
        user.setUsername(phone);
        user.setPhone(phone);
        //设置初始密码
        String initPassword="1";

        //生成盐值
        String salt = StrUtils.getComplexRandomString(32);
        user.setSalt(salt);
        //加密加盐
        String password = MD5Utils.encrypByMd5(initPassword + salt);
        user.setPassword(password);
        user.setState(1);
        user.setCreatetime(new Date());
        return user;
    }
}
